﻿#include "OperatorsSemiInfiniteFluidManager.h"

#include "PickDataProvider/GUIPickInfo.h"
#include "PickDataProvider/PickedDataProvider.h"

#include "GUIDialog/GUISubSystemDialog/SemiInfiniteFluidDialog.h"
#include "GUIDialog/GUISubSystemDialog/SemiInfiniteFluidConnectDialog.h"

#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKCore/FITKVec3DAlg.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscNodeList.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEASubSysSemiInfiniteFluid.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEAFace.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsTriangles.h"
#include "FITK_Interface/FITKInterfaceModel/FITKAbstractElement.h"

#include "OperatorsInterface/GraphEventOperator.h"
#include "updateBrowserTable.h"

#include <QMessageBox>
#include <QDebug>

namespace ModelOper
{
    bool OperatorsSemiInfiniteFluidManager::execGUI()
    {
        if (_senderName == "actionCreateSemiInfiniteFluid") {
            GraphData::PickedDataProvider* provider = GraphData::PickedDataProvider::getInstance();
            if (provider == nullptr)return false;
            //清除拾取对象所有的连接
            QObject::disconnect(provider, SIGNAL(sig_pickedOver()), nullptr, nullptr);

            GUI::GUIPickInfoStru pickStr;
            pickStr._pickObjType = GUI::GUIPickInfo::PickObjType::POBJDiscNode;
            pickStr._pickMethod = GUI::GUIPickInfo::PickMethod::PMSingle;
            GUI::GUIPickInfo::ClearPickInfo();
            GUI::GUIPickInfo::SetPickInfo(pickStr);

            connect(provider, SIGNAL(sig_pickedOver()), this, SLOT(slotPickOverEvent()));
        }
        else if (_senderName == "actionEditSemiInfiniteFluid") {
            int objID = -1;
            this->argValue(objID_String, objID);
            GUI::SemiInfiniteFluidDialog* dialog = new GUI::SemiInfiniteFluidDialog(objID, this, false);
            dialog->show();

        }
        else if (_senderName == "actionConnectSemiInfiniteFluid") {
            GUI::SemiInfiniteFluidConnectDialog* dialog = new GUI::SemiInfiniteFluidConnectDialog(this, FITKAPP->getGlobalData()->getMainWindow());
            connect(dialog, &QDialog::accepted, this, &OperatorsSemiInfiniteFluidManager::execProfession);
            dialog->show();
            //GraphData::PickedDataProvider* provider = GraphData::PickedDataProvider::getInstance();
            //if (provider == nullptr)return false;
            ////清除拾取对象所有的连接
            //QObject::disconnect(provider, SIGNAL(sig_pickedOver()), nullptr, nullptr);

            //GUI::GUIPickInfoStru pickStr;
            //pickStr._pickObjType = GUI::GUIPickInfo::PickObjType::POBJSEASubSystem;
            //pickStr._pickMethod = GUI::GUIPickInfo::PickMethod::PMIndividually;
            //GUI::GUIPickInfo::ClearPickInfo();
            //GUI::GUIPickInfo::SetPickInfo(pickStr);

            //connect(provider, SIGNAL(sig_pickedOver()), this, SLOT(slotPickJunOverEvent()));
            
        }
        return false;
    }

    bool OperatorsSemiInfiniteFluidManager::execProfession()
    {
        int objId = -1;
        this->argValue(objID_String, objId);

        // Added by ChengHaotian 刷新可视化对象。
        //@{
        EventOper::GraphEventOperator* operGraph = FITKOPERREPO->getOperatorT<EventOper::GraphEventOperator>("GraphPreprocess");
        if (operGraph)
        {
            operGraph->updateGraph(objId, true);
        }
        //@}

        //更新表格
        ModelOper::updateBrowserTable();


        return false;
    }

    void OperatorsSemiInfiniteFluidManager::slotPickOverEvent()
    {
        GraphData::PickedDataProvider* provider = GraphData::PickedDataProvider::getInstance();
        if (provider == nullptr)return;
        disconnect(provider, SIGNAL(sig_pickedOver()), this, SLOT(slotPickOverEvent()));

        QList<GraphData::PickedData*> pickList = provider->getPickedList();
        QList<int> idList = {};
        for (GraphData::PickedData* pickData : pickList) {
            if (pickData == nullptr)continue;
            for (auto str : pickData->getPickedDiscNodes()) {
                idList.append(str._id);
            }
        }
        if (idList.size() == 0) {
            QMessageBox box(QMessageBox::Warning, "", QString(tr("Unselected point!")), QMessageBox::Ok);
            box.exec();
            GUI::GUIPickInfo::ClearPickInfo();
            return;
        }

        GUI::SemiInfiniteFluidDialog* dialog = new GUI::SemiInfiniteFluidDialog(-1, this, true);
        dialog->setNodeID(idList[0]);
        dialog->show();

        GUI::GUIPickInfo::ClearPickInfo();
    }

    void OperatorsSemiInfiniteFluidManager::slotPickJunOverEvent()
    {
        GraphData::PickedDataProvider* provider = GraphData::PickedDataProvider::getInstance();
        if (provider == nullptr)return;
        disconnect(provider, SIGNAL(sig_pickedOver()), this, SLOT(slotPickJunOverEvent()));
        QList<GraphData::PickedData*> pickList = provider->getPickedList();
        QList<int> idList = {};
        QList<GraphData::PickedFaceData> pickFaceList = {};
        for (GraphData::PickedData* pickData : pickList) {
            if (pickData == nullptr)continue;
            idList.append(pickData->getPickedDataObjId());
            pickFaceList.append(pickData->getPickedSEAFaces());
        }
        GUI::GUIPickInfo::ClearPickInfo();

        Acoustics::FITKAcousticsDiscModel* discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (discModel == nullptr && discModel->getSEAModel() == nullptr)return;
        Acoustics::FITKAcousticsSEASubSysManager* subManager = discModel->getSEAModel()->getSEASubSysManager();
        if (subManager == nullptr)return;
        Acoustics::FITKSEAFaceManager* faceManager = discModel->getSEAModel()->getSEAFaceManager();
        if (faceManager == nullptr)return;
        Acoustics::FITKAcousticsDiscNodeList* nodeList = discModel->getNodes();
        if (nodeList == nullptr)return;
        
        if (idList.size() != 2 || pickFaceList.size() == 0) {
            QMessageBox box(QMessageBox::Warning, "", QString(tr("No two subsystems were selected!")), QMessageBox::Ok);
            box.exec();
            return;
        }
        int semiID = idList[0];
        int subID = idList[1];

        Acoustics::FITKSEASubSysSemiInfiniteFluid* semiData = dynamic_cast<Acoustics::FITKSEASubSysSemiInfiniteFluid*>(subManager->getDataByID(semiID));
        if (semiData != nullptr && semiData->getSEASubSysType() != Acoustics::FITKAbstractSEASubSys::SEASubSysType::SEASemiIInfiniteFluid) {
            QMessageBox box(QMessageBox::Warning, "", QString(tr("The preference is not a semi-infinite fluid!")), QMessageBox::Ok);
            box.exec();
            return;
        }

        Acoustics::FITKAbstractSEASubSys* subData = subManager->getDataByID(subID);
        if (subData != nullptr) {
            auto type = subData->getSEASubSysType();
            switch (type) {
            case Acoustics::FITKAbstractSEASubSys::SEASSNone:
            case Acoustics::FITKAbstractSEASubSys::SEABeam:
            case Acoustics::FITKAbstractSEASubSys::SEACavity:
            case Acoustics::FITKAbstractSEASubSys::SEASemiIInfiniteFluid: {
                QMessageBox box(QMessageBox::Warning, "", QString(tr("Semi-infinite fluids support only connections to plates!")), QMessageBox::Ok);
                box.exec();
                return;
            }
            }
        }

        //获取连接点
        double connectPoint[3] = { 0,0,0 };
        //int faceID = pickFaceList[0].FaceId;
        //int eleIndex = pickFaceList[0].ElementId;
        calculatePoint(pickFaceList[0], connectPoint);
        Core::FITKNode* point = nodeList->getNodeByID(semiData->getNodeID());
        Core::FITKNode point1(connectPoint[0], connectPoint[1], connectPoint[2]);
        double distance = Core::Distance(*point, point1);

        //添加半无限流体连接
        Acoustics::FITKSEASubSysSEIFConnectedSubSys* semiDataConnect = new Acoustics::FITKSEASubSysSEIFConnectedSubSys();
        semiDataConnect->setSubSysID(subID);
        semiDataConnect->setConnectPos(connectPoint);
        semiDataConnect->setDistance(distance);
        semiData->appendDataObj(semiDataConnect);

        EventOper::GraphEventOperator* operGraph = FITKOPERREPO->getOperatorT<EventOper::GraphEventOperator>("GraphPreprocess");
        if (operGraph)
        {
            operGraph->updateGraph(semiID, true);
        }
    }

    void OperatorsSemiInfiniteFluidManager::calculatePoint(GraphData::PickedFaceData pickData, double * point)
    {
        Acoustics::FITKAcousticsDiscModel* discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (discModel == nullptr && discModel->getSEAModel() == nullptr)return;
        Acoustics::FITKSEAFaceManager* faceManager = discModel->getSEAModel()->getSEAFaceManager();
        if (faceManager == nullptr)return;
        Acoustics::FITKAcousticsDiscNodeList* nodeList = discModel->getNodes();
        if (nodeList == nullptr)return;

        int faceID = pickData.FaceId;
        int eleIndex = pickData.ElementId;

        QList<int> allNodes = {};
        Acoustics::FITKAbstractSEAFace* face = faceManager->getDataByID(faceID);
        if (face != nullptr) {
            Acoustics::FITKAcousticsTriangles* eleS = face->getTriangleMesh();
            if (eleS != nullptr && eleS->getElementCount() > eleIndex) {
                Interface::FITKAbstractElement* ele = eleS->getElementAt(eleIndex);
                if (ele != nullptr) allNodes = ele->getAllNodes();
            }
        }
        if (allNodes.size() == 0)return;

        QList<Core::FITKNode*> points = {};
        for (int nodeID : allNodes) {
            Core::FITKNode* point = nodeList->getNodeByID(nodeID);
            if (point == nullptr)continue;
            double node[3] = { 0,0,0 };
            points.append(point);
        }
        if (points.size() != 3)return;

        point[0] = (points[0]->x() + points[1]->x() + points[2]->x()) / 3;
        point[1] = (points[0]->y() + points[1]->y() + points[2]->y()) / 3;
        point[2] = (points[0]->z() + points[1]->z() + points[2]->z()) / 3;
    }
}